物件導向程式設計(Object-Oriented Programming,OOP)是一種以「物件」為核心的程式設計範式。它將資料和操作資料的方法組織在一起,形成了所謂的「物件」。這種方法有助於創建更加模組化、可重用和易於維護的程式碼。
Java 作為一種純物件導向的程式設計語言,擁抱 OOP 的概念。在 Java 中,除了基本資料型別外,幾乎所有東西都是物件。Java 的物件導向特性包括:
在 Java 中,類別和物件是物件導向程式設計的基本構建塊。類別是物件的藍圖或模板,而物件則是類別的實例。
類別在 Java 中的基本結構如下:
public class Car {
// 屬性(成員變數)
private String brand;
private String model;
private int year;
// 建構子
public Car(String brand, String model, int year) {
this.brand = brand;
this.model = model;
this.year = year;
}
// 方法
public void startEngine() {
System.out.println("引擎啟動!");
}
// Getter 和 Setter 方法
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
// 其他 getter 和 setter 方法...
}
一旦定義了類別,我們就可以創建該類別的物件並使用它:
public class Main {
public static void main(String[] args) {
// 創建 Car 類別的物件
Car myCar = new Car("Toyota", "Corolla", 2022);
// 使用物件的方法
myCar.startEngine();
// 使用 getter 方法
System.out.println("我的車是 " + myCar.getBrand());
}
}
建構子是一種特殊的方法,用於初始化新創建的物件。它的名稱必須與類別名稱相同,且沒有回傳型別。
public class Person {
private String name;
private int age;
// 無參數建構子
public Person() {
this.name = "未知";
this.age = 0;
}
// 帶參數建構子
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
封裝是物件導向程式設計的四大基本概念之一,它指的是將資料和操作資料的方法綁定在一起,並對外部隱藏內部的實現細節。在 Java 中,封裝主要通過存取修飾符和 getter/setter 方法來實現。
Java 提供了四種存取修飾符,用於控制類別成員的可見性:
為了實現封裝,我們通常將類別的屬性設為 private,然後提供公開的 getter 和 setter 方法來存取和修改這些屬性。
public class Student {
private String name;
private int age;
// Getter 方法
public String getName() {
return name;
}
// Setter 方法
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 0 && age < 120) { // 加入驗證邏輯
this.age = age;
} else {
System.out.println("無效的年齡");
}
}
}
封裝的主要優點包括:
例如,我們可以在 setter 方法中加入驗證邏輯,確保資料的正確性:
public class BankAccount {
private double balance;
public double getBalance() {
return balance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
} else {
System.out.println("存款金額必須大於零");
}
}
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
} else {
System.out.println("提款金額無效或餘額不足");
}
}
}
通過封裝,我們可以確保物件的內部狀態始終保持一致和有效,同時為未來的修改和擴展提供了靈活性。
繼承是物件導向程式設計中的一個核心概念,它允許我們基於現有的類別創建新的類別。在 Java 中,繼承使用 extends
關鍵字來實現。
基本語法如下:
public class 子類別 extends 父類別 {
// 子類別的成員
}
例如:
public class Animal {
protected String name;
public void eat() {
System.out.println(name + " 正在吃東西");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println(name + " 汪汪叫");
}
}
在這個例子中,Dog
類別繼承了 Animal
類別,因此 Dog
類別擁有 Animal
類別的所有公開和受保護的成員。
子類別可以覆寫(override)父類別的方法,提供自己的實現:
public class Cat extends Animal {
@Override
public void eat() {
System.out.println(name + " 優雅地吃東西");
}
}
使用 @Override
註解可以確保我們確實在覆寫父類別的方法。
super
關鍵字用於呼叫父類別的方法或建構子:
public class Bird extends Animal {
public Bird(String name) {
super(name); // 呼叫父類別的建構子
}
@Override
public void eat() {
super.eat(); // 呼叫父類別的 eat 方法
System.out.println(name + " 啄食");
}
}
繼承的主要優點包括:
繼承要注意:
多型是物件導向程式設計的另一個重要概念,允許我們以一致的方式處理不同類別的物件。在 Java 中,多型主要通過方法覆寫和介面實現。
多型允許一個介面有多種實現。這意味著可以使用父類別的參考變數來引用子類別的物件。
方法多型是通過方法覆寫實現的。例如:
public class Animal {
public void makeSound() {
System.out.println("動物發出聲音");
}
}
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("狗:汪汪!");
}
}
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("貓:喵喵!");
}
}
public class Main {
public static void main(String[] args) {
Animal animal1 = new Dog();
Animal animal2 = new Cat();
animal1.makeSound(); // 輸出:狗:汪汪!
animal2.makeSound(); // 輸出:貓:喵喵!
}
}
Java 也支援某些運算子的多型,如 +
運算子可用於數字相加或字串連接。
Animal animal = new Dog(); // 向上轉型
Dog dog = (Dog) animal; // 向下轉型
if (animal instanceof Cat) {
Cat cat = (Cat) animal; // 使用 instanceof 檢查類型安全
}
抽象類別和介面是 Java 中實現抽象化的兩種重要機制,它們在設計複雜系統時扮演著關鍵角色。
抽象類別是一種不能被實例化的類別,它可以包含抽象方法(沒有實作的方法)和具體方法。
abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// 抽象方法
public abstract double getArea();
// 具體方法
public void displayColor() {
System.out.println("顏色是:" + color);
}
}
class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}
抽象類別的主要用途:
介面是一種完全抽象的類型,只包含抽象方法的宣告。
interface Drawable {
void draw();
}
class Rectangle extends Shape implements Drawable {
private double width;
private double height;
public Rectangle(String color, double width, double height) {
super(color);
this.width = width;
this.height = height;
}
@Override
public double getArea() {
return width * height;
}
@Override
public void draw() {
System.out.println("繪製一個矩形");
}
}
介面的主要特點:
默認方法(Default Method)
定義位置:默認方法是在接口中定義的,使用 default 關鍵字。
目的:允許接口添加新方法而不影響實現該接口的類。這樣可以保持向後兼容性。
實現:默認方法可以有具體的實現,實現類可以選擇使用默認實現或重寫該方法。
interface MyInterface {
default void myDefaultMethod() {
System.out.println("這是默認方法");
}
}
靜態方法(Static Method)
定義位置:靜態方法可以在類中或接口中定義,但在接口中使用 static 關鍵字。
目的:靜態方法屬於類本身,而不是類的實例。可以直接通過類名調用。
無法重寫:靜態方法不能被實現類重寫,因為它們不屬於對象的實例。
class MyClass {
static void myStaticMethod() {
System.out.println("這是靜態方法");
}
}
選擇使用抽象類別還是介面取決於具體需求:
在物件導向程式設計中,遵循一些設計原則可以幫助我們創建更加靈活、可維護和可擴展的系統。以下是一些重要的設計原則:
SOLID 是五個物件導向設計原則的縮寫:
設計模式是解決常見設計問題的可重用解決方案。一些常見的設計模式包括:
組合優於繼承:盡可能使用組合來實現程式碼重用,而不是過度依賴繼承。
程式設計到介面,而不是具體實現:這增加了程式的靈活性。
保持類別的高內聚性和低耦合性:每個類別應該專注於單一任務,並儘量減少對其他類別的依賴。
遵循 DRY 原則(Don't Repeat Yourself):避免程式碼重複。
YAGNI 原則(You Ain't Gonna Need It):只實現當前需要的功能,避免過度設計。
使用設計模式,但不要濫用:設計模式是工具,不是目標。
本篇文章同步刊載: JYI.TW
筆者個人的網站: JUNYI